// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Fabric;
using System.Fabric.Description;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ActorRuntimeManager
{
    public partial class LaunchActorForm : Form
    {
        private FabricClient m_client;
        public bool Successful = false;
        public string m_chosenActorApplication;
        public string m_actorType;

        public LaunchActorForm(FabricClient fabricClient, string chosenActorApplication)
        {
            InitializeComponent();

            // Populate comboBoxActorType
            m_chosenActorApplication = chosenActorApplication;
            m_actorType = MainForm.s_actorAccountingInfo.Where(x => x.FabricAppName.Equals(chosenActorApplication)).Select(x => x.AppName).FirstOrDefault();
            labelActorType.Text = m_actorType;
            if (m_actorType.StartsWith("Stateless"))
            {
                this.textBoxNumReplicas.Enabled = false;
                this.comboBoxPersonality.Enabled = true;
                this.comboBoxStateType.Enabled = true;
            }
            else
            {
                this.textBoxNumReplicas.Enabled = true;
                this.comboBoxPersonality.Enabled = false;
                this.comboBoxStateType.Enabled = false;
                this.textBoxNumReplicas.Text = "2";
            }
            
            m_client = fabricClient;
            comboBoxStateType.SelectedIndex = 0;
            comboBoxPersonality.SelectedIndex = 0;
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void buttonLaunch_Click(object sender, EventArgs e)
        {

            var newActorName = textBoxActorName.Text;
            if (String.IsNullOrWhiteSpace(newActorName))
            {
                MessageBox.Show("You must provide a name for your new actor");
                return;
            }

            var appInfo = MainForm.s_actorAccountingInfo.Where(x => x.AppName.Equals(m_actorType)).First();
            if (m_actorType.StartsWith("Stateless"))
            {
                var partitionInfo = new SingletonPartitionSchemeDescription(); // TODO: Can we cache one of these in a static variable?
                var statelessDescription = new StatelessServiceDescription();
                statelessDescription.ServiceName = new Uri(String.Format("{0}/{1}", appInfo.FabricAppName, newActorName));
                statelessDescription.ServiceTypeName = appInfo.ReplicaType;
                statelessDescription.PartitionSchemeDescription = partitionInfo;
                statelessDescription.ApplicationName = new Uri(appInfo.FabricAppName);
                var initializationInfo = String.Format("StateType={0};Personality={1}", comboBoxStateType.SelectedItem.ToString(), comboBoxPersonality.SelectedItem.ToString());
                statelessDescription.InitializationData = Encoding.UTF8.GetBytes(initializationInfo);

                try
                {
                    m_client.ServiceManager.CreateServiceAsync(statelessDescription).Wait();
                    Successful = true;
                    this.Close();
                }
                catch (FabricElementAlreadyExistsException)
                {
                    MessageBox.Show("This actor already exists");
                }
                catch (AggregateException ae)
                {
                    // Ignore if this stems from FabricElementAlreadyExistsException
                    if ((ae.GetBaseException() is FabricElementAlreadyExistsException))
                    {
                        MessageBox.Show("This actor already exists");
                    }
                    else
                    {
                        MessageBox.Show("Exception: " + ae.GetBaseException());
                    }
                }
            }
            else
            {
                int numReplicas = 0;
                if (!Int32.TryParse(textBoxNumReplicas.Text, out numReplicas))
                {
                    MessageBox.Show("Must specify valid number of replicas");
                    return;
                }

                if (numReplicas <= 0)
                {
                    MessageBox.Show("Number of replicas must be one or more.");
                    return;
                }

                var partitionInfo = new SingletonPartitionSchemeDescription(); // TODO: Can we cache one of these in a static variable?
                StatefulServiceDescription statefulDescription = new StatefulServiceDescription();
                statefulDescription.ServiceName = new Uri(appInfo.FabricAppName + "/" + newActorName);
                statefulDescription.ServiceTypeName = appInfo.ReplicaType;
                statefulDescription.PartitionSchemeDescription = partitionInfo;
                statefulDescription.TargetReplicaSetSize = numReplicas;
                statefulDescription.HasPersistedState = false;
                statefulDescription.MinReplicaSetSize = ((numReplicas % 2) == 0) ? (numReplicas + 1) / 2 : (numReplicas / 2) + 1;
                statefulDescription.ApplicationName = new Uri(appInfo.FabricAppName);

                // Create a service/actor, flowing exceptions to the caller
                try
                {
                    m_client.ServiceManager.CreateServiceAsync(statefulDescription).Wait();
                    Successful = true;
                    this.Close();
                }
                catch (FabricElementAlreadyExistsException)
                {
                    MessageBox.Show("That actor already exists");
                }
                catch (AggregateException ae)
                {
                    // Ignore if this stems from FabricElementAlreadyExistsException
                    if ((ae.GetBaseException() is FabricElementAlreadyExistsException))
                    {
                        MessageBox.Show("That actor already exists");
                    }
                    else
                    {
                        MessageBox.Show("Exception: " + ae.GetBaseException());
                    }
                }
            }

        }
    }
}
